﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Diagnostics;

namespace TechnicalAnalysisEngine.Tests
{
    [TestClass]
    public class TestMFI
    {
        List<double> inputHighs;
        List<double> inputLows;
        List<double> inputCloses;
        List<int> inputVolumes;
        List<double> expectedValues;

        int expectedOffset;
        int periods;

        [TestInitialize]
        public void Initialize()
        {
            inputHighs = new List<double>()
            {
                24.83,24.76,25.16,25.58,25.68,25.34,25.29,25.13,25.28,25.39,25.54,25.60,25.74,25.72,25.67,
                25.45,25.32,25.26,25.04,25.01,25.31,25.12,24.69,24.55,24.27,24.27,24.60,24.48,24.56,25.16
            };

            inputLows = new List<double>()
            {
                24.32,24.60,24.78,24.95,24.81,25.06,24.85,24.75,24.93,25.03,25.05,25.06,25.54,25.46,25.29,
                25.17,24.92,24.91,24.83,24.71,25.03,24.34,24.27,23.89,23.78,23.72,24.20,24.24,23.43,24.27
            };

            inputCloses = new List<double>()
            {
                24.75,24.71,25.04,25.55,25.07,25.11,24.89,25.00,25.05,25.34,25.06,25.45,25.56,25.56,25.41,
                25.37,25.04,24.92,24.88,24.97,25.05,24.45,24.57,24.02,23.88,24.20,24.28,24.33,24.44,25.00
            };

            inputVolumes = new List<int>()
            {
                18730,12272,24691,18358,22964,15919,16067,16568,16019,9774,22573,12987,10907,5799,7395,5818,
                7165,5673,5625,5023,7457,11798,12366,13295,9257,9691,8870,7169,11356,13379
            };

            expectedValues = new List<double>()
            {
                49.47,45.11,36.27,28.41,31.53,33.87,41.30,42.80,31.83,23.76,26.51,24.07,22.38,22.18,21.53,30.84
            };

            periods = 14;
            expectedOffset = 14;
        }

        [TestMethod]
        public void TestMFIValues()
        {
            var result = AnalysisEngine.MFI(inputHighs, inputLows, inputCloses, inputVolumes, periods);

            Assert.AreEqual(expectedValues.Count, result.Values.Count);
            Assert.AreEqual(expectedOffset, result.StartIndexOffset);

            string message = null;
            bool testResult = true;

            for (int i = 0; i < result.Values.Count; i++)
            {
                if (!TestHelpers.EqualsWithTolerance(result.Values[i], expectedValues[i], 1)) // 1% tolerance from expected results
                {
                    message = string.Format("Values do not match at position {0}, expected: {1}, actual: {2} ",
                        i, expectedValues[i], result.Values[i]);

                    testResult = false;
                    break;
                }
            }

            Assert.IsTrue(testResult, message);
        }

        [TestMethod]
        public void TestMFIPerformance()
        {
            Random random = new Random();
            var randomlyGeneratedHighs = new List<double>();
            var randomlyGeneratedLows = new List<double>();
            var randomlyGeneratedCloses = new List<double>();
            var randomlyGeneratedVolumes = new List<int>();

            for (int i = 0; i < 10000; i++)
            {
                randomlyGeneratedHighs.Add(random.Next(85, 90));
                randomlyGeneratedLows.Add(random.Next(80, 85));
                randomlyGeneratedCloses.Add(random.Next(83, 87));
                randomlyGeneratedVolumes.Add(random.Next(50000, 100000));
            }

            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            AnalysisEngine.MFI(randomlyGeneratedHighs, randomlyGeneratedLows, randomlyGeneratedCloses, randomlyGeneratedVolumes, periods);

            stopWatch.Stop();
            Console.WriteLine(string.Format("ATR, {0} values, {1} μs", randomlyGeneratedHighs.Count, stopWatch.ElapsedTicks / 10));
        }
    }
}
